package objects

import (
	"dos_framework/apiServer/heartbeat"
	"dos_framework/apiServer/locate"
	"dos_framework/es"
	"dos_framework/rs"
	"dos_framework/utils"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"
)

//Go 语法学习:变量或函数名首字母小写，仅在包内使用，如put 小写仅在objects包内可见

func put(w http.ResponseWriter, r *http.Request) {
	hash := utils.GetHashFromHeader(r.Header)
	if hash == "" {
		log.Println("Mising object hash in digest")
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	size := utils.GetSizeFromHeader(r.Header)
	//object := strings.Split(r.URL.EscapedPath(), "/")[2]
	//c, e := storeObject(r.Body, url.PathEscape(hash))
	c, e := storeObject(r.Body, hash, size)
	if e != nil {
		log.Println(e)
		w.WriteHeader(c)
		return

	}
	if c != http.StatusOK {
		log.Println("Failed to store object")
		w.WriteHeader(c)
		return

	}
	name := strings.Split(r.URL.EscapedPath(), "/")[2]
	// size := utils.GetSizeFromHeader(r.Header)

	e = es.AddVersion(name, hash, size)
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(c)
}

func storeObject(r io.Reader, hash string, size int64) (int, error) {

	if locate.Exist(url.PathEscape(hash)) {
		return http.StatusOK, nil
	}

	stream, e := putStream(url.PathEscape(hash), size)
	if e != nil {
		return http.StatusServiceUnavailable, e

	}
	/*
		io.Copy(stream, r)
		/*以数据流形式处理来自客户端的请求，接口服务调用io.copy()方法从对象put请求正文直接读取对象数据写入数据服务，
		是因为客户端上传的对象大小可能超出接口服务节点内存，不能把整个对象读入内存再进行处理

	*/
	reader := io.TeeReader(r, stream)
	d := utils.CalculateHash(reader)
	if d != hash {
		stream.Commit(false)
		return http.StatusBadRequest, fmt.Errorf("object hash mismatch, calculated:%s, requested:%s", d, hash)
	}
	stream.Commit(true)
	//e = stream.Close()

	return http.StatusOK, nil

}

/*
func putStream(hash string, size int64) (*objectstream.TempPutStream, error) {
	server := heartbeat.ChooseRandomDataServer()
	fmt.Println("putStream:", server)
	if server == "" {
		return nil, fmt.Errorf("can not find any dataServer")
	}

	return objectstream.NewTempPutStream(server, hash, size)
}
*/

func putStream(hash string, size int64) (*rs.RSPutStream, error) {
	servers := heartbeat.ChooseRandomDataServers(rs.ALL_SHARDS, nil)
	//fmt.Println("putStream:", server)
	if len(servers) != rs.ALL_SHARDS {
		return nil, fmt.Errorf("can not find enough dataServers")
	}

	return rs.NewRSPutStream(servers, hash, size)
}
